﻿namespace Groundwork.Extensions
{
    using System;
    using System.IO;
    using System.Security;
    using System.Security.Permissions;
    using System.Xml;
    using System.Xml.Linq;
    using Groundwork.Core;
	using Groundwork.Extensions;
	
    /// <summary>
    /// File IO Extensions
    /// </summary>
    public static class IO
    {
        /// <summary>
        /// Saves the string to a file
        /// </summary>
        /// <param name="value">string to save</param>
        /// <param name="path">file path</param>
        /// <param name="fileName">filename to save</param>
        /// <exception cref="System.Security.SecurityException">Thrown if an error occurs attempting to create the file</exception>
        /// <exception cref="System.IO.IOException">Thrown if a the file exists at the specified location</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if Path or fileName are null or empty</exception>
        /// <example>
        ///   <code>
        ///   <![CDATA[
        /// string myString = "Hello World";
        /// myString.SaveToFile(@"c:\myFolder","hello.txt");
        /// ]]>
        ///   </code>
        ///   </example>
        /// <remarks>Assumes that access is permitted to the location being written to.</remarks>
        public static void SaveToFile(this string value, string path, string fileName)
        {
            path.ThrowIfNull();
            fileName.ThrowIfNull();
            string builtPath = StaticUtility.BuildPath(path);
            string fullPath = Path.Combine(builtPath, fileName);
            if (!File.Exists(fullPath))
            {
                try
                {
                    FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write, path);
                    permission.Demand();
                    File.WriteAllText(fullPath, value);
                }
                catch                
                {
                    throw new SecurityException(string.Format("Unable to gain access to {0}", fullPath));
                } 
            }
            else
            {
                throw new IOException(fullPath);
            }
        }

        /// <summary>
        /// Builds a path in the file system using the path provided. If it does not exist the path is created.
        /// </summary>
        /// <param name="path">path to create</param>
        /// <returns>path that was created</returns>
        public static string BuildPath(this string path)
        {
            try
            {
                return StaticUtility.BuildPath(path);
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Loads a document at a given path and outputs a valid XDocument
        /// </summary>
        /// <param name="path">path to load</param>
        /// <returns>Valid XDocument</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if path is null or empty</exception>
        /// <example>
        ///   <code><![CDATA[
        /// XDocument myDoc = "".XDocumentFromFile(@"c:\myfolder\data.xml");
        /// ]]></code></example>
        public static XDocument XDocumentFromFile(this string path)
        {
            path.ThrowIfNullOrEmpty();
            string fileContent = ReadFile(path);
            fileContent.ThrowIfNullOrEmpty(string.Empty);
            XDocument document = XDocument.Parse(fileContent);
            return document;
        }

        /// <summary>
        /// Loads an Xml Document from the file system and outputs
        /// </summary>
        /// <param name="path">path of file to load</param>
        /// <returns>Xml Document</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if path is null or empty</exception>
        /// <example>
        ///   <code><![CDATA[
        /// XmlDocument myDoc = "".XmlDocumentFromFile(@"c:\myfolder\data.xml");
        /// ]]></code></example>
        public static XmlDocument XmlDocumentFromFile(this string path)
        {
            path.ThrowIfNullOrEmpty();
            string fileContent = ReadFile(path);
            fileContent.ThrowIfNullOrEmpty(string.Empty);
            XmlDocument document = new XmlDocument();
            document.LoadXml(fileContent);
            return document;
        }

        /// <summary>
        /// Reads the file specified
        /// </summary>
        /// <param name="path">file to read</param>
        /// <returns>string content of the file</returns>
        /// <exception cref="System.IO.FileNotFoundException">Thrown if the file could not be found at the specified location</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if path is null or empty</exception>
        /// <example>
        ///   <code><![CDATA[
        /// string myDoc = "".ReadFile(@"c:\myfolder\data.txt");
        /// ]]></code></example>
        internal static string ReadFile(string path)
        {
            path.ThrowIfNullOrEmpty();
            string fileContent = string.Empty;
            if (File.Exists(path))
            {
                try
                {
                    FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, path);
                    permission.Demand();
                    fileContent = File.ReadAllLines(path).ToString();
                }
                catch
                {
                    throw new FileNotFoundException(path);
                }
            }

            return fileContent;
        }
    }
 }
